﻿var extScope = [];

/**
 * Retrieve nested item from object/array
 * @param {Object|Array} obj
 * @param {String} path dot separated
 * @param {*} def default value ( if result undefined )
 * @returns {*}
 */
function Path(obj, path, def) {
    var i, len;

    for (i = 0, path = path.split('.'), len = path.length; i < len; i++) {
        if (!obj || typeof obj !== 'object') return def;
        obj = obj[path[i]];
    }

    if (obj === undefined) return def;
    return obj;
}

/* Global settings variable for Formly settings... */
function GetConfig() {
    this.url = null, 
    this.method = "GET",
    this.params = {},
    this.headers = { 'Cache-Control': 'no-cache' }
};

function PostConfig() {
    this.url = null,
    this.method = "POST",
    this.data = {},
    this.headers = { 'Cache-Control': 'no-cache' }
};

function FormlySettings() {
    this.load = null,
    this.send = null,
    this.container = '',
    this.callbackSuccess = null,
    this.callbackError = null,
    this.callbackReset = null,
    this.shortcutCallback = null,
    this.onloadCallback = null,
    this.controllerName = null
};

FormlySettings.prototype.setLoad = function (urlCnfg) {
    this.load = urlCnfg;
};

FormlySettings.prototype.setSend = function (urlCnfg) {
    this.send = urlCnfg;
};

FormlySettings.prototype.createPostConfig = function (url, params) {
    var retValue = new PostConfig();

    retValue.url = url;
    retValue.data = params;

    return retValue;
};

FormlySettings.prototype.createGetConfig = function (url, params) {
    var retValue = new GetConfig();

    retValue.url = url;
    retValue.params = params;

    return retValue;
};

function FormlyManager(settings) {
//function FormlyManager(loadUrl, sendUrl, container, callbackSuccess, callbackError, shortcutCallback, onloadCallback) {

    'use strict';

    var internalSetts = [];
    if (!Array.isArray(settings)) {
        internalSetts = [settings];
    } else {
        internalSetts = settings;
    }

    var app = angular.module('formlyExample', ['formly', 'formlyBootstrap', 'FormlyNET'], function config(formlyConfigProvider, CustomTypesProvider) {
        formlyConfigProvider.extras.removeChromeAutoComplete = true;

        $.each(internalSetts, function (index, item) {
            formlyConfigProvider.setType(CustomTypesProvider.getTypes(item.container));
            return false;
        });
    });

    $.each(internalSetts, function (index, item) {
        var loadUrl = item.load;
        var sendUrl = item.send;
        var container = item.container;
        var callbackSuccess = item.callbackSuccess;
        var callbackError = item.callbackError;
        var shortcutCallback = item.shortcutCallback;
        var onloadCallback = item.onloadCallback;
        var controllerName = item.controllerName;
        var resetCallback = item.callbackReset;

        //
        //var app = angular.module('formlyExample', ['formly', 'formlyBootstrap', 'FormlyNET'], function config(formlyConfigProvider, CustomTypesProvider) {
        //    formlyConfigProvider.extras.removeChromeAutoComplete = true;

        //    formlyConfigProvider.setType(CustomTypesProvider.getTypes(container));
        //});

        //app.controller('MainCtrl', function MainCtrl($http, $scope, $q, CustomTypes, FieldsService) {
        app.controller(controllerName, function($http, $scope, $q, CustomTypes, FieldsService) {
            var vm = this;

            extScope[controllerName] = $scope;

            //vm.settings = item;

            //an array of files selected
            vm.files = [];

            //listen for the file selected event
            $scope.$on("fileSelected", function (event, args) {
                $scope.$apply(function () {
                    //add the file object to the scope's files collection
                    vm.files.push(args.file);
                });
            });

            // funcation assignment
            vm.onSubmit = onSubmit;
            vm.onReset = onReset;

            vm.model = {};

            vm.Load = function (loadUrl) {
                vm.loadingData = FieldsService.getFields(loadUrl).then(function (result) {

                    if ($.isArray(result.data)) {
                        // Edit...
                        vm.fields = JSON.parse(result.data[0], function (key, value) {
                            return Reviver(key, value);
                        });
                        vm.model = JSON.parse(result.data[1]);
                    } else {
                        // Insert...
                        vm.fields = JSON.parse(result.data, function (key, value) {
                            return Reviver(key, value);
                        });
                        vm.model = {};
                    }

                    /* check all fields to bind, eventually, the addOn button click event... */
                    AddOnButtons(vm.fields);

                    /* checks for uiSelect2 fileds to bind the refreshItems standard Callback... */
                    BindCallback(vm.fields);

                    vm.originalFields = angular.copy(vm.fields);

                    if (onloadCallback != undefined) {
                        onloadCallback();
                    }

                });
            }

            // Note, normally I prefer to use the router and resolve
            // async dependencies into my controller, but I think
            // this gives you the idea of what you're supposed to do...  api/formly/
            // if url is webform webmethod: 'TestFormly2.aspx/LoadData' -> POST -> JSON.parse(result.data.d)
            // if uel is Web APi controller: api/formly/LoadFields -> GET -> JSON.parse(result.data)
            vm.loadingData = FieldsService.getFields(loadUrl).then(function (result) {

                if ($.isArray(result.data)) {
                    // Edit...
                    vm.fields = JSON.parse(result.data[0], function (key, value) {
                        return Reviver(key, value);
                    });
                    vm.model = JSON.parse(result.data[1]);
                } else {
                    // Insert...
                    vm.fields = JSON.parse(result.data, function (key, value) {
                        return Reviver(key, value);
                    });
                    vm.model = {};
                }

                /* check all fields to bind, eventually, the addOn button click event... */
                AddOnButtons(vm.fields);

                /* checks for uiSelect2 fileds to bind the refreshItems standard Callback... */
                BindCallback(vm.fields);

                vm.originalFields = angular.copy(vm.fields);

                if (onloadCallback != undefined) {
                    onloadCallback();
                }

            });

            $scope.SetGetUrl = function (url, container) {
                var settings = new FormlySettings();
                settings.container = container;
                settings.setLoad(settings.createGetConfig(url));

                return settings.load;
            }

            $scope.SetPostUrl = function (url, container) {
                var settings = new FormlySettings();
                settings.container = container;
                settings.setLoad(settings.createPostConfig(url));

                return settings.load;
            }

            $scope.ShowDatepicker = function () {
                datepicker.open($event)
            }

            function Reviver(key, value) {
                if (value && (typeof value === 'string') && value.indexOf("function") === 0) {
                    // we can only pass a function as string in JSON ==> doing a real function
                    var jsFunc = new Function('return ' + value)();
                    return jsFunc;
                }

                return value;
            }

            function AddOnButtons(fields) {
                $.each(fields, function (index, item) {
                    var objR = Path(item, 'templateOptions.addonRight');

                    if (objR !== undefined) {
                        if (objR.onClick !== undefined) {
                            var fR = objR.onClick;
                            objR.onClick = function (options, scope) { item.type == 'asyncselect' ? '' : eval(fR)(options, scope); }
                        }
                    }

                    var objL = Path(item, 'templateOptions.addonLeft');
                    if (objL !== undefined) {
                        if (objL.onClick !== undefined) {
                            var fL = objL.onClick;
                            objL.onClick = function (options, scope) { item.type == 'asyncselect' ? '' : eval(fR)(options, scope); }
                        }
                    }
                });
            }

            function BindCallback(fields) {
                $.each(fields, function (index, item) {
                    if (item.type == 'ui-select-single-search') {
                        item.templateOptions.refresh = refreshItems;
                    }
                });
            }

            function refreshItems(name, field) {
                var promise;
                var temp = '';

                if (!name) {
                    promise = $q.when({ results: [] });
                } else {
                    var data = { name: name, field: field };
                    var endpoint = field.templateOptions.callback;

                    temp = field.templateOptions.label;
                    field.templateOptions.label = temp + ' ...searching...';
                    promise = $http.post(endpoint, data);
                }

                return promise.then(function (response) {
                    field.templateOptions.options = response.data;
                    field.templateOptions.label = temp;
                });
            }

            function SaveDataAndFiles(vm, url) {
                $http({
                    method: 'POST',
                    url: url,
                    //IMPORTANT!!! You might think this should be set to 'multipart/form-data' 
                    // but this is not true because when we are sending up files the request 
                    // needs to include a 'boundary' parameter which identifies the boundary 
                    // name between parts in this multi-part request and setting the Content-type 
                    // manually will not set this boundary parameter. For whatever reason, 
                    // setting the Content-type to 'false' will force the request to automatically
                    // populate the headers properly including the boundary parameter.
                    headers: { 'Content-Type': undefined },
                    //This method will allow us to change how the data is sent up to the server
                    // for which we'll need to encapsulate the model data in 'FormData'
                    transformRequest: function (data) {
                        var formData = new FormData();
                        //need to convert our json object to a string version of json otherwise
                        // the browser will do a 'toString()' on the object which will result 
                        // in the value '[Object object]' on the server.
                        formData.append("model", angular.toJson(data.model));
                        //now add all of the assigned files
                        for (var i = 0; i < data.files.length; i++) {
                            //add each file to the form data and iteratively name them
                            formData.append("file" + i, data.files[i]);
                        }
                        return formData;
                    },
                    //Create an object that contains the model and files which will be transformed
                    // in the above transformRequest method
                    data: { model: vm.model, files: vm.files }
                }).
                success(function (data, status, headers, config) {
                    vm.files = [];

                    if (typeof window.parent.parent.dialogClose == 'function') {
                        window.parent.parent.dialogClose();
                    }

                    if (callbackSuccess != undefined) {
                        callbackSuccess(response.data);
                    }
                }).
                error(function (data, status, headers, config) {
                    vm.files = [];

                    if (status != 200) {
                        if (data != '') {
                            if (callbackError != undefined) {
                                callbackError(data);
                            } else {
                                alert(data);
                            }
                        } else {
                            if (callbackError != undefined) {
                                callbackError(statusText);
                            } else {
                                alert(statusText);
                            }
                        }
                    }
                });
            };

            function onReset() {
                vm.model = {};
                vm.form.$setUntouched();

                if (resetCallback != undefined) {
                    resetCallback(vm);
                }
            }

            function onSubmit() {

                if ((vm.files != null) && (vm.files.length > 0)) {

                    SaveDataAndFiles(vm, sendUrl.url);

                } else {
                    var data = JSON.stringify(vm.model);
                    //alert(data, null, 2);

                    if ((sendUrl == '') || (sendUrl == undefined)) {

                        if (shortcutCallback != undefined) {
                            shortcutCallback(data);
                        }

                    } else {
                        sendUrl.data = data;
                        //$http.post(sendUrl).then(function successCallback(response) {
                        $http(sendUrl).then(function successCallback(response) {
                            //alert(response.data);

                            //Then on the button in the iFrame, call this on client click: 
                            if (typeof window.parent.parent.dialogClose == 'function') {
                                window.parent.parent.dialogClose();
                            }

                            if (callbackSuccess != undefined) {
                                callbackSuccess(response.data);
                            }

                        }, function errorCallback(response) {
                            // called asynchronously if an error occurs
                            // or server returns response with an error status.
                            if (response.status != 200) {
                                if (response.data != '') {
                                    if (callbackError != undefined) {
                                        callbackError(response.data);
                                    } else {
                                        alert(response.data);
                                    }
                                } else {
                                    if (callbackError != undefined) {
                                        callbackError(response.statusText);
                                    } else {
                                        alert(response.statusText);
                                    }
                                }
                            }
                        });
                    }
                }
            }
        });
    });
};


    function destroyApp(app) {
        /*
         * Iterate through the child scopes and kill 'em
         * all, because Angular 1.2 won't let us $destroy()
         * the $rootScope
         */
        var $rootScope = app.get('$rootScope');
        var scope = $rootScope.$$childHead;
        while (scope) {
            var nextScope = scope.$$nextSibling;
            scope.$destroy();
            scope = nextScope;
        }

        /*
         * Iterate the properties of the $rootScope and delete 
         * any that possibly were set by us but leave the 
         * Angular-internal properties and functions intact so we 
         * can re-use the application.
         */
        for (var prop in $rootScope) {
            if (($rootScope[prop])
                && (prop.indexOf('$$') != 0)
                && (typeof ($rootScope[prop]) === 'object')
                ) {
                $rootScope[prop] = null;
            }
        }
    }